/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun<lingyun@email.com>
 *                  All rights reserved.
 *
 *       Filename:  socket_server.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(11/03/25)
 *         Author:  LingYun <lingyun@email.com>
 *      ChangeLog:  1, Release initial version on "11/03/25 16:47:50"
 *                 
 ********************************************************************************/
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

#define MSG_STR "Hello Lingyun IoT Studio Client.\n"

void print_usage(char *progname)
{
	printf("%s usagae: \n", progname);
	printf("-p(--port): sepcify server listen port.\n");
	printf("-h(--Help): print this help information.\n");

	return ;
}

int main(int argc, char **argv)
{
	int						sockfd = -1;
	int						rv = -1;
	struct sockaddr_in  	servaddr;
	struct sockaddr_in		cliaddr;
	socklen_t				len;
	int 					port = 0;
	char					buf[1024];
	int						clifd;
	int						ch;
	int						on = 1;
	struct option			opts[]={
			{"port", required_argument, NULL, 'p'},
			{"help", no_argument, NULL, 'h'},
			{NULL,  0, NULL, 0}
	};

	while((ch = getopt_long(argc, argv, "p:h", opts, NULL)) !=-1 )
	{
		switch(ch)
		{
			case 'p':
				port=atoi(optarg);
				break;
			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}

	if(!port)
	{
		print_usage(argv[0]);
		return 0;
	}

	sockfd=socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Craet socket failure: %s\n", strerror(errno));
		return -1;
	}
	printf("Creat socket[%d] successfully!\n", sockfd);

	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	memset(&servaddr, 0, sizeof(servaddr));

	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(port);
	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

	rv=bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	if(rv < 0)
	{
		printf("Socket[%d] bind on port[%d] failure:%s\n", sockfd, port, strerror(errno));
		return -2;
	}

	listen(sockfd, 13);
	printf("Strat to listen on port [%d]!\n", port);

	while(1)
	{
		printf("Start accept new client incoming...\n");

		clifd=accept(sockfd, (struct sockaddr *)&cliaddr, &len);
		if(clifd < 0)
		{
			printf("Accept new client failure: %s\n", strerror(errno));
			continue;
		}
		printf("Accept new client[%s:%d] successfully!\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

		memset(buf, 0, sizeof(buf));
		rv=read(clifd, buf, sizeof(buf));
		if(rv < 0)
		{
			printf("Read data from cliet by socket[%d] failure: %s\n", clifd, strerror(errno));
			close(clifd);
			continue;
		}
		else if(rv == 0)
		{
			printf("Socket[%d] get disconnected.\n", clifd);
			continue;
		}
		else if(rv > 0)
		{
			printf("Read %d bytes data from client: %s\n", rv, buf);
		}

		rv=write(clifd, MSG_STR, strlen(MSG_STR));
		if(rv < 0)
		{
			printf("Write to client by scokfd[%d] failure: %s\n", sockfd, strerror(errno));
			close(clifd);
			continue;
		}

		printf("Close client socket[%d]\n", clifd);
		close(clifd);

	}

	close(sockfd);
}

